package mirrormonkey.util.netevent.message;

import mirrormonkey.util.netevent.EventManager;
import mirrormonkey.util.netevent.message.MessageEventCreator;
import mirrormonkey.util.netevent.message.tools.MockMessage;
import mirrormonkey.util.netevent.message.tools.MockMessageConnection;
import mirrormonkey.util.netevent.message.tools.MockMessageListener;
import mirrormonkey.util.netevent.message.tools.OtherMockMessage;

import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;

import com.jme3.network.Message;

/**
 * Integration test: For the whole package <tt>mirrormonkey.util.netevent</tt>,
 * test if messages are processed and relayed correctly by the framework.
 * 
 * @author Philipp Christian Loewner
 * 
 */
public class MessageEventTest {

	private static final Message[] MESSAGES = { new MockMessage(),
			new MockMessage() };

	private static final Message[] NO_MESSAGES = {};

	private static final Message[] FIRST_MESSAGE = { MESSAGES[0] };

	private static final Message[] OTHER_MESSAGE = { new OtherMockMessage() };

	private static EventManager manager;

	private static MockMessageConnection connection;

	private static MessageEventCreator creator;

	private static MockMessageListener[] listeners;

	@BeforeClass
	public static void setUpClass() {
		manager = new EventManager();

		connection = new MockMessageConnection();

		creator = manager.getMessageListener();

		listeners = new MockMessageListener[] { new MockMessageListener(),
				new MockMessageListener() };
	}

	@After
	public void tearDown() {
		MockMessageListener.reset(listeners);
	}

	private void sendAll(Message[] messages) {
		for (Message m : messages) {
			creator.messageReceived(connection, m);
		}
	}

	public void checkReceived(Message[] messages) {
		MockMessageListener.checkReceived(listeners, connection, messages);
	}

	/**
	 * Tests if messages are relayed to generic message listeners
	 */
	@Test
	public void testGenericMessage() {
		for (MockMessageListener l : listeners) {
			manager.addMessageListener(l);
		}

		sendAll(MESSAGES);
		checkReceived(NO_MESSAGES);

		manager.processEvents();
		checkReceived(MESSAGES);
	}

	/**
	 * Tests if generic listener remove works
	 */
	@Test
	public void testGenericRemove() {
		manager.removeMessageListener(listeners[1]);

		sendAll(FIRST_MESSAGE);
		manager.processEvents();

		listeners[0].checkReceived(connection, FIRST_MESSAGE);
		listeners[1].checkReceived(connection, NO_MESSAGES);
		MockMessageListener.reset(listeners);

		manager.removeMessageListener(listeners[0]);

		sendAll(FIRST_MESSAGE);
		manager.processEvents();
		listeners[0].checkReceived(connection, NO_MESSAGES);
	}

	/**
	 * Test if messages are relayed to listeners listening to specific classes
	 */
	@Test
	public void testSpecificMessageMultiClass() {
		for (MockMessageListener l : listeners) {
			manager.addMessageListener(l, MockMessage.class,
					OtherMockMessage.class);
		}

		sendAll(MESSAGES);
		manager.processEvents();

		checkReceived(MESSAGES);
		MockMessageListener.reset(listeners);

		sendAll(OTHER_MESSAGE);
		manager.processEvents();

		checkReceived(OTHER_MESSAGE);
	}

	/**
	 * Test if specific class message listeners can be removed from classes
	 */
	@Test
	public void testSpecificRemoveMultiClass() {
		for (MockMessageListener l : listeners) {
			manager.removeMessageListener(l, OtherMockMessage.class);
		}

		sendAll(MESSAGES);
		manager.processEvents();

		checkReceived(MESSAGES);
		MockMessageListener.reset(listeners);

		sendAll(OTHER_MESSAGE);
		manager.processEvents();

		checkReceived(NO_MESSAGES);

		for (MockMessageListener l : listeners) {
			manager.removeMessageListener(l, MockMessage.class);
		}

		sendAll(MESSAGES);
		manager.processEvents();

		checkReceived(NO_MESSAGES);
	}

	/**
	 * Test if specific class listeners can be removed from a class without
	 * affecting the other listeners registered to that class
	 */
	@Test
	public void testSpecificRemoveSingleClass() {
		for (MockMessageListener l : listeners) {
			manager.addMessageListener(l, MockMessage.class);
		}
		manager.removeMessageListener(listeners[1], MockMessage.class);

		sendAll(MESSAGES);
		manager.processEvents();

		listeners[0].checkReceived(connection, MESSAGES);
		listeners[1].checkReceived(connection, NO_MESSAGES);
	}

}
